// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

// ************************************************************************* //
//  File: avtDeferExpressionBaseFilter.C
// ************************************************************************* //

#include <avtDeferExpressionBaseFilter.h>

#include <ExpressionList.h>
#include <ParsingExprList.h>

#include <InvalidVariableException.h>


// ****************************************************************************
//  Method: avtDeferExpressionBaseFilter constructor
//
//  Programmer: childs -- generated by xml2avt
//  Creation:   Thu Sep 1 06:35:41 PDT 2005
//
// ****************************************************************************

avtDeferExpressionBaseFilter::avtDeferExpressionBaseFilter()
{
}


// ****************************************************************************
//  Method: avtDeferExpressionBaseFilter destructor
//
//  Programmer: childs -- generated by xml2avt
//  Creation:   Thu Sep 1 06:35:41 PDT 2005
//
//  Modifications:
//
// ****************************************************************************

avtDeferExpressionBaseFilter::~avtDeferExpressionBaseFilter()
{
}


// ****************************************************************************
//  Method: avtDeferExpressionBaseListFilter::SetupExpressionList
//
//  Purpose:
//      Sets up the expression list of what this filter should modify.
//
//  Programmer: Hank Childs
//  Creation:   September 23, 2010
//
// ****************************************************************************

void
avtDeferExpressionBaseFilter::SetupExpressionList(void)
{
    std::vector<std::string> varsToEvaluate;
    GetVariablesToEvaluate(varsToEvaluate);

    std::vector<Expression> customExpressions;
    GetCustomExpressions(customExpressions);

    //
    // The pipeline specification may already contain two flavors of
    // expressions.  Expressions whose evaluation should be deferred and
    // expressions that will be evaluated at the top of the pipeline.
    // 
    // The EEF determines which variables an expression depends on and adds 
    // those expressions to the contract.  We want to perform 
    // this duty for only those expression whose evaluation we are deferring.
    //
    // The easiest way to do this is to modify the expression list.  We can
    // make the expressions that are being deferred appear to be the only
    // expressions that exist.  That way, this instance of the EEF will not
    // interfere with the expressions that should be processed normally
    // (ie at the top of the pipeline).
    //
    ExpressionList *el = ParsingExprList::Instance()->GetList();
    ExpressionList new_el;
    for (size_t j = 0 ; j < varsToEvaluate.size() ; j++)
    {
        bool foundMatch = false;
        for (int i = 0 ; i < el->GetNumExpressions() ; i++)
            if (varsToEvaluate[j] == el->GetExpressions(i).GetName())
            {
                bool replacedByCustom = false;
                for (size_t k = 0 ; k < customExpressions.size() ; k++)
                     if (varsToEvaluate[j] == customExpressions[k].GetName())
                     {
                          new_el.AddExpressions(customExpressions[k]);
                          replacedByCustom = true;
                          break;
                     }
                if (!replacedByCustom)
                    new_el.AddExpressions(el->GetExpressions(i));
                foundMatch = true;
                break;
            }
        if (!foundMatch)
            EXCEPTION1(InvalidVariableException, varsToEvaluate[j].c_str());

        // If this is a vector, then look for the magnitude as well.
        std::string newName = varsToEvaluate[j] + "_AVT_mag";
        for (int i = 0 ; i < el->GetNumExpressions() ; i++)
            if (newName == el->GetExpressions(i).GetName())
                new_el.AddExpressions(el->GetExpressions(i));
    }

    orig_el = *el;
    *el = new_el;
}


// ****************************************************************************
//  Method: avtDeferExpressionBaseListFilter::ExamineContract
//
//  Purpose:
//      A hook that allows the derived types to infer the name of the
//      variable we are processing (for operators that generate
//      expressions).
//
//  Programmer: Hank Childs
//  Creation:   September 23, 2010
//
// ****************************************************************************

void
avtDeferExpressionBaseFilter::ExamineContract(avtContract_p c)
{
    InferVariableNameFromContract(c);
    avtExpressionEvaluatorFilter::ExamineContract(c);
}


// ****************************************************************************
//  Method: avtDeferExpressionBaseFilter::ModifyContract
//
//  Purpose:
//      Allows the EEF to declare which variables it needs for the expressions
//      whose evaluation are being deferred.
//
//  Programmer: Hank Childs
//  Creation:   September 1, 2005
//
//  Modifications:
//    Brad Whitlock, Fri Mar 9 17:31:44 PST 2007
//    Updated because of small change to ExpressionList.
//
//    Mark C. Miller, Wed Jun 17 14:27:08 PDT 2009
//    Replaced CATCHALL(...) with CATCHALL.
//
//    Hank Childs, Thu Sep 23 16:48:04 PDT 2010
//    Refactored method so derived types can set up new expressions.
//
// ****************************************************************************

avtContract_p
avtDeferExpressionBaseFilter::ModifyContract(avtContract_p spec)
{
    SetupExpressionList();

    avtContract_p rv = spec;
    TRY
    {
        rv = avtExpressionEvaluatorFilter::ModifyContract(spec);
        RestoreExpressionList();
    }
    CATCHALL
    {
        RestoreExpressionList();

        RETHROW;
    }
    ENDTRY

    return rv;
}


// ****************************************************************************
//  Method: avtDeferExpressionBaseListFilter::Execute
//
//  Purpose:
//      Sets up the expressions we want to calculate and then calls execute.
//
//  Programmer: Hank Childs
//  Creation:   September 23, 2010
//
// ****************************************************************************

void
avtDeferExpressionBaseFilter::Execute()
{
    SetupExpressionList();
    avtExpressionEvaluatorFilter::Execute();
    RestoreExpressionList();
}


// ****************************************************************************
//  Method: avtDeferExpressionBaseListFilter::RestoreExpressionList
//
//  Purpose:
//      We set up a custom expression list for execution.  This is the method
//      to restore that expression list so it doesn't affect the rest of the 
//      pipeline.
//
//  Programmer: Hank Childs
//  Creation:   September 23, 2010
//
// ****************************************************************************

void
avtDeferExpressionBaseFilter::RestoreExpressionList()
{
    ExpressionList *el = ParsingExprList::Instance()->GetList();
    *el = orig_el;
}


